﻿using AgencyManagerSystem.Common;
using MySql.Data.MySqlClient;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using Dapper;
using Dapper.Contrib.Extensions;


namespace AgencyManagerSystem.DataFetcher
{
    public static class DBHelper
    {
        //static IDbConnection connection;
        private static IDbConnection CreateDbConnection()
        {
            IDbConnection connection = null;
            if (connection == null)
            {
                LogHelper.Log(typeof(DBHelper).Name,String.Format("GETDBCONNECTION:尝试取得数据库连接:{2}@{0}:{1}", Variable.SQL_HOST, Variable.SQL_PORT,Variable.SQL_DBNAME));
                connection = new MySqlConnection();
                connection.ConnectionString = String.Format("Server={0};Database={1};Uid={2};Pwd={3};Port={4};CharSet={5};ConnectionTimeout=30",
                    Variable.SQL_HOST, Variable.SQL_DBNAME, Variable.SQL_USER, Variable.SQL_PASSWORD, Variable.SQL_PORT, Variable.SQL_CHARSET);
            }
            return connection;
        }
        public static IDbConnection GetDbConnection(IDbTransaction transaction)
        {
            if (transaction != null)
                return transaction.Connection;
            return null;
        }
        
        public static IEnumerable<T> Query<T>(this IDbTransaction dbTransaction, string sql, DynamicParameters param = null)
        {
            IDbConnection conn = dbTransaction.Connection;
            return conn.Query<T>(sql, param, dbTransaction);
        }
        public static T ExecuteScalar<T>(this IDbTransaction dbTransaction, string sql, DynamicParameters param = null)
        {
            IDbConnection conn = dbTransaction.Connection;
            return conn.ExecuteScalar<T>(sql, param, dbTransaction);
        }
        public static int Execute(this IDbTransaction dbTransaction, string sql, DynamicParameters param = null)
        {
            IDbConnection conn = dbTransaction.Connection;
            return conn.Execute(sql, param, dbTransaction);
        }
        public static long Insert<T>(this IDbTransaction dbTransaction,T data) where T: DBModel
        {
            IDbConnection conn = dbTransaction.Connection;
            return conn.Insert(data, dbTransaction);
        }
        public static bool Update<T>(this IDbTransaction dbTransaction, T data) where T : DBModel
        {
            IDbConnection conn = dbTransaction.Connection;
            return conn.Update(data, dbTransaction);
        }
        public static bool Delete<T>(this IDbTransaction dbTransaction, T data) where T : DBModel
        {
            IDbConnection conn = dbTransaction.Connection;
            return conn.Delete(data, dbTransaction);
        }
        private static Hashtable TranCache = Hashtable.Synchronized( new Hashtable());
        public static bool Alive()
        {
            try
            {
                if (MyHttpContext.Current == null) return false;
                string tranCode = (String)MyHttpContext.Current.Items["current_tran_code"];
                return (TranCache.ContainsKey(tranCode));
            }
            catch(Exception ex)
            {
                return false;
            }
        }
        public static IDbTransaction GetTran()
        {
            string tranCode="";
            return GetTran(out tranCode);
        }
        public static IDbTransaction GetTran(out string tranCode)
        {
            tranCode = "";
            if(!MyHttpContext.Current.Items.ContainsKey("current_tran_code"))
            {
                tranCode = CreateTran();
                MyHttpContext.Current.Items.Add("current_tran_code", tranCode);
            }
            else
            {
                object o_tran = MyHttpContext.Current.Items["current_tran_code"];
                if(o_tran==null||o_tran.ToString().Trim()=="")
                {
                    tranCode = CreateTran();
                    MyHttpContext.Current.Items["current_tran_code"] = tranCode;
                }
                else
                {
                    tranCode = o_tran.ToString();
                }
            }
            if (String.IsNullOrEmpty(tranCode))
            {
                LogHelper.Err(typeof(DBHelper).Name, "GETTRAN:无法在上下文中取得TRANCODE事务实例");
                return null;
            }
            object cache = TranCache[tranCode];
            if (cache == null)
            {
                LogHelper.Err(typeof(DBHelper).Name, String.Format("GETTRAN:事务实例TRANCODE {0} 已经被移除", tranCode));
                return null;
            }
            IDbTransaction result = cache as IDbTransaction;
            LogHelper.Log(typeof(DBHelper).Name, String.Format("GETTRAN:取得事务实例TRANCODE {0}成功", tranCode));
            return result;
        }
        private static string CreateTran()
        {
            IDbConnection connection = CreateDbConnection();
            if (connection.State != ConnectionState.Open)
            {
                try
                {
                    connection.Open();
                    LogHelper.Log(typeof(DBHelper).Name, "CREATETRAN:数据库连接已打开!");
                }
                catch(Exception ex)
                {
                    LogHelper.Err(typeof(DBHelper).Name, ex.Message + "-" + ex.StackTrace);
                    return "";
                }
            }
            try
            {
                IDbTransaction dbTransaction = connection.BeginTransaction();
                string tranCode = dbTransaction.GetHashCode().ToString();
                TranCache.Add(tranCode, dbTransaction);
                LogHelper.Log(typeof(DBHelper).Name, String.Format("事务实例transaction {0} 已被创建", tranCode));
                if(TranCache.Count>Definer.TRANPOOL_WARNSIZE)
                {
                    LogHelper.Log(typeof(DBHelper).Name, String.Format("事务实例池数量已达警告阈值{0}", TranCache.Count));
                }
                return tranCode;
            }
            catch (Exception ex)
            {
                LogHelper.Err(typeof(DBHelper).Name,ex.Message+"-"+ ex.StackTrace);
                connection.Close();
                MySqlConnection.ClearPool((MySqlConnection)(connection));
            }
            return "";
        }
        public static bool Commit(AmsCode asmCode)
        {
            return Commit(asmCode == AmsCode.Succ);
        }
        public static bool Commit(bool commit)
        {
            bool result = false;
            string tranCode;
            IDbTransaction dbTransaction = GetTran(out tranCode);
            if (dbTransaction == null)
            {
                LogHelper.Warn(typeof(DBHelper).Name, String.Format("COMMIT:无法根据 transaction code {0} 找到事务实例", tranCode));
                return false;
            }
            try
            {
                if (commit)
                    dbTransaction.Commit();
                else
                    dbTransaction.Rollback();
                LogHelper.Log(typeof(DBHelper).Name, String.Format("COMMIT:事务 {0} 提交或回滚完成", tranCode));
                result = true;
            }
            catch (Exception ex)
            {
                LogHelper.Err(typeof(DBHelper).ToString(), ex.Message + "-" + ex.StackTrace);
                result = false;
            }
            finally
            {
                LogHelper.Log(typeof(DBHelper).Name, String.Format("COMMIT:事务 {0} 将被丢弃，并从缓存中移除", tranCode));
                dbTransaction.Connection.Close();
                dbTransaction.Connection.Dispose();
                MySqlConnection.ClearPool((MySqlConnection)(dbTransaction.Connection));
                TranCache.Remove(tranCode);
                MyHttpContext.Current.Items.Remove("current_tran_code");
            }
            return result;
        }
    }
}
